import { Vec3 } from "cc";

export class nUtils {
    /**
     * @Date: 2022-02-1 21:36:14
     * @LastEditors: iwae
     * @description: 减少数字精度
     * @param {*} value
     * @param {*} decimals 保留小数点位数
     */
    static roundNumber(value: number, decimals: number) {
        const factor = Math.pow(10, decimals);
        return Math.round(value * factor) / factor;
    }
    //+ Jonas Raoni Soares Silva
    //@ http://jsfromhell.com/math/is-point-in-poly [rev. #0]
    static isPointInPoly(poly, pt) {
        for (var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
            ((poly[i].z <= pt.z && pt.z < poly[j].z) || (poly[j].z <= pt.z && pt.z < poly[i].z)) && (pt.x < (poly[j].x - poly[i].x) * (pt.z - poly[i].z) / (poly[j].z - poly[i].z) + poly[i].x) && (c = !c);
        return c;
    }

    static isVectorInPolygon(vector: Vec3, polygon, vertices) {
        // reference point will be the centroid of the polygon
        // We need to rotate the vector as well as all the points which the polygon uses
        var lowestPoint = 100000;
        var highestPoint = -100000;
        const polygonVertices = [];

        polygon.vertexIds.forEach((vId) => {
            lowestPoint = Math.min(vertices[vId].y, lowestPoint);
            highestPoint = Math.max(vertices[vId].y, highestPoint);
            polygonVertices.push(vertices[vId]);
        });

        if (vector.y < highestPoint + 0.5 && vector.y > lowestPoint - 0.5 &&
            this.isPointInPoly(polygonVertices, vector)) {
            return true;
        }
        return false;
    }


    /**
     * @Date: 2022-02-1 21:28:45
     * @LastEditors: iwae
     * @description: Unity Vec3 翻译，移动到指定目标点
     * @param {Vec3} out 输出坐标，返回下一帧的位置
     * @param {Vec3} current 当前坐标，需要使用.clone()
     * @param {Vec3} target 目的地坐标
     * @param {number} maxDistanceDelta 每帧速度
     */
    static MoveTowards(out: Vec3, current: Vec3, target: Vec3, maxDistanceDelta: number) {
        // avoid vector ops because current scripting backends are terrible at inlining
        const toVector_x = target.x - current.x;
        const toVector_y = target.y - current.y;
        const toVector_z = target.z - current.z;
        const sqdist = toVector_x * toVector_x + toVector_y * toVector_y + toVector_z * toVector_z;
        if (sqdist == 0 || (maxDistanceDelta >= 0 && sqdist <= maxDistanceDelta * maxDistanceDelta)) {
            out.set(target);
            return true;
        }
        const dist = Math.sqrt(sqdist);
        out.set(current.x + toVector_x / dist * maxDistanceDelta,
            current.y + toVector_y / dist * maxDistanceDelta,
            current.z + toVector_z / dist * maxDistanceDelta)
        return false;
    }

    static triarea2(a: Vec3, b: Vec3, c: Vec3) {
        const ax = b.x - a.x;
        const az = b.z - a.z;
        const bx = c.x - a.x;
        const bz = c.z - a.z;
        return bx * az - ax * bz;
    }


    static mergeVertices(geometry: { vertices, faces }) {
        const verticesMap = {};
        let indices, unique = new Array, changes = [], key, i, il, face;
        for (i = 0, il = geometry.vertices.length; i < il; i++) {
            key = geometry.vertices[i];
            if (verticesMap[key] == null) {
                verticesMap[key] = i;
                unique.push(key);
                changes[i] = unique.length - 1;
            }
            else {
                changes[i] = changes[verticesMap[key]];
            }
        };

        const faceIndicesToRemove = [];
        for (i = 0, il = geometry.faces.length; i < il; i++) {
            face = geometry.faces[i];
            face[0] = changes[face[0]];
            face[1] = changes[face[1]];
            face[2] = changes[face[2]];
            indices = face;
            let dupIndex = -1;
            for (let n = 0; n < 3; n++) {
                if (indices[n] == indices[(n + 1) % 3]) {
                    dupIndex = n;
                    faceIndicesToRemove.push(i);
                    break;
                }
            }
        }
        for (i = faceIndicesToRemove.length - 1; i >= 0; i--) {
            let idx = faceIndicesToRemove[i];
            geometry.faces.splice(idx, 1);
        };
        geometry.vertices = unique;

    }


    /**
     * @Date: 2022-02-25 21:35:06
     * @LastEditors: iwae
     * @description: 返回数组内随机内容
     * @param {*} list
     */
    static sample(list) {
        return list[Math.floor(Math.random() * list.length)];
    }


    /**
     * @Date: 2022-02-26 00:50:52
     * @LastEditors: iwae
     * @description: 比较2个Vec3是否相等
     * @param {Vec3} a
     * @param {Vec3} b
     */
    static vequal(a: Vec3, b: Vec3) {
        return Vec3.distance(a, b) < 0.00001;
    }
}

